package guru.util;

import guru.util.ObjectCall.ObjectCall;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Dictionary;
import java.util.Hashtable;

import org.apache.log4j.Logger;

/**
 * La clase Commando representa una infraestructura para interfaz de comando.
 * 
 * 1. Interfaz de comando 2. .Properties 3. Configuracion remota por interfaz de comando.
 */

public class Commander extends Thread{
    static Logger logger = Logger.getLogger(Commander.class);

    static final int CLIENT_PORT = 8887;
    static final int LISTENER_PORT = 8888;

    int port;
    DatagramSocket socket;
    String tmpstr;
    private boolean stop = false;
    Commandable server;
    Params params;

    public Commander(String initFilePath, String mandatoryParams, Commandable server) throws Exception {
        this.server = server;
        params = new Params(initFilePath, mandatoryParams);

        port = params.intValue("commander.port", LISTENER_PORT);
        socket = new DatagramSocket(port);
    }

    public String getValue(String key, String def) {
        return (params.getValue(key, def));
    }

    public String getValue(String key) {
        return (params.getValue(key));
    }

    public int intValue(String key, int def) {
        return (params.intValue(key, def));
    }

    public void finalize() {
        stop = true;
    }

    public void run() {
        String tmpstr;

        try {
            //InetAddress group = InetAddress.getByName("230.0.0.1");
            //socket.joinGroup(group);

            DatagramPacket packet;
            byte[] buf;
            byte[] buf2;
            InetAddress target;

            executeInitialCommands();

            while (!stop) {
                // RECIBIR
                try {
                    buf = new byte[256];
                    packet = new DatagramPacket(buf, buf.length);

                    socket.receive(packet);

                    String received = new String(packet.getData());

                    // PROCESAR
                    tmpstr = process(received.trim());

                    // CONTESTAR
                    buf2 = tmpstr.getBytes();
                    target = packet.getAddress();
                    packet = new DatagramPacket(buf2, buf2.length, target, CLIENT_PORT);
                    socket.send(packet);
                } finally {

                }
            }

            //socket.leaveGroup(group);
            socket.close();
            logger.info("Commander listener down.");

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /*
     * private String process(String command){ if(command.equalsIgnoreCase("c1")){ return("c1
     * executed");
     *  }
     * 
     * return("no action taken: received '"+command+"'"); }
     */

    private String process(String command) {

        Dictionary map = new Hashtable();
        map.put("server", server);
        ObjectCall call = null;

        try {
            call = new ObjectCall("server." + command, map);
        } catch (Exception e) {
            logger.error("Error while procesing the directives: " + e, e);
            return ("Error while procesing the directives: " + e);
        }

        if (call != null) {
            Object o = call.getReturn();
            if (o != null) { return (o.toString()); }
        }

        return ("unknown result");

    }

    void executeInitialCommands() {
        boolean stop = false;
        int line = 1;
        String cmd;

        server.initCommands();

        while (!stop) {
            try{
                if ((cmd = (String) params.props.get("commander.cmd." + (line++))) == null) {
                    stop = true;
                } else {
                    logger.info(process(cmd));
                }
            }finally{

            }
        }

    }

    public static void main(String argv[]) {
        int port = 4447;
        byte[] buf;

        if ((argv.length > 2) || (argv.length == 0)) {
            System.out.println("java Commander [<port#>] <command>");
            return;
        }

        if (argv.length == 2) {
            try {
                port = new Integer(argv[0]).intValue();
                buf = argv[1].getBytes();
            } catch (Exception e) {
                System.out.println("java Commander [<port#>] <command>");
                return;
            }
        } else {
            buf = argv[0].getBytes();
        }

        try {
            DatagramSocket socket = new DatagramSocket(CLIENT_PORT);
            //InetAddress group = InetAddress.getByName("230.0.0.1");
            //socket.joinGroup(group);
            InetAddress target = InetAddress.getByName("127.0.0.1");

            DatagramPacket packet;
            packet = new DatagramPacket(buf, buf.length, target, port);

            socket.send(packet);

            buf = new byte[256];
            packet = new DatagramPacket(buf, buf.length);

            socket.receive(packet);

            String received = new String(packet.getData());

            System.out.println(received.trim());

            socket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}